/*
 * $Id$
 */
package ua.org.energy.vkek.site.server;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Text;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import ua.org.energy.vkek.site.model.Article;
import ua.org.energy.vkek.site.model.ArticleTag;

public class ArticleUtils {

    private EntityManager em;

    public ArticleUtils(EntityManager em) {
        this.em = em;
    }

    public Article attachToTag(String tagName, Article article) throws DataIOException {
        healtCheck(article);
        checkUnique(article.getArticleTitle());
        return glueToTag(tagName, article);
    }

    private Article glueToTag(String tagName, Article article) throws DataIOException {
        ArticleTag target = TagUtils.findArticleTag(tagName, em);
        if (target != null) {
            article.setTag(target);
            article.setArticleDate(new Date());
            target.getArticles().add(article);
            //         em.merge(article);
            em.persist(article);
            return article;
        } else {
            throw new DataIOException("could not find target Tag");
        }
    }

    /**
     * обновляет заголовок статьи, обновляется, также дата публикации
     *
     * @param oldArticleTitle
     * @param newArticleTitle
     * @return article after update
     * @throws DataIOException
     */
    public Article updateTitle(String oldArticleTitle, String newArticleTitle) throws DataIOException {
        checkUnique(newArticleTitle);
        Article oldval = findArticle(oldArticleTitle);
        if (oldval != null) {
            oldval.setArticleTitle(newArticleTitle);
            return update(oldval);
        } else {
            throw new DataIOException("could not find Article for update");
        }
    }

    public Article updateContent(Key articleKey, Text newContent) throws DataIOException {
        Article oldval = findArticle(articleKey);
        if (oldval != null) {
            oldval.setContent(newContent);
            return update(oldval);
        } else {
            throw new DataIOException("could not find Article for update");
        }
    }

    /**
     * Обновляет "разумно" :-) статью 
     * @see Article
     *
     * @param key
     * @param title
     * @param content
     * @return
     * @throws DataIOException
     */
    public Article updateWise(Key key, String title, String content) throws DataIOException {
        Article article = findArticle(key);
        if (article != null) {
            article.setArticleTitle(title);
            article.setContent(new Text(content));
            return update(article);
        } else {
            throw new DataIOException("non existent Article could not be updated");
        }

    }

    public Article update(Article article) throws DataIOException {
        healtCheck(article);
        if (article.getIdent() != null) { //статья имеет ключ следовательно уже есть/была в базе
            try {
                article.setArticleDate(new Date());
                em.merge(article);
                return article;
            } catch (Exception e) {
                throw new DataIOException(e.getMessage());
            }
        } else {
            //If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
            //см. JSR 220: Enterprise JavaBeansTM,Version 3.0  Java Persistence API раз. 3.2.4.1
            throw new DataIOException("non existent Article could not be updated");
        }
    }

    public void delete(String articleTitle) throws DataIOException {
        try {
            Article oldval = findArticle(articleTitle);
            if (oldval != null) {
                em.remove(oldval);
            } else {
                throw new DataIOException("could not find Article for delete");
            }
        } catch (Exception e) {
            throw new DataIOException(e.getMessage());
        }
    }

    public void delete(Key articleKey) throws DataIOException {
        try {
            Article oldval = findArticle(articleKey);
            if (oldval != null) {
                em.remove(oldval);
            } else {
                throw new DataIOException("could not find Article for delete");
            }
        } catch (Exception e) {
            throw new DataIOException(e.getMessage());
        }
    }

    public static Article findArticle(String articleTitle, EntityManager em) {
        try {
            Object obj = em.createNamedQuery("Article.findByTitle").setParameter("artTitle", articleTitle).getSingleResult();
            return (Article) obj;
        } catch (NoResultException e) {
            return null;
        }
    }

    public Article findArticle(Key key) {
        return em.find(Article.class, key);
    }

    public Article findArticle(String articleTitle) {
        return findArticle(articleTitle, this.em);
    }

    public List<Article> listAll() {
        return (List<Article>) em.createNamedQuery("Article.findAll").getResultList();
    }

    public  List<Article> listForTag(String tagName) {
        ArticleTag tag = TagUtils.findArticleTag(tagName, em);
        if (tag != null) {
            return tag.getArticles();
        } else {
            return null;
        }
    }

    private void healtCheck(Article article) throws DataIOException {
        if ((article == null) || (article.getArticleTitle() == null)) {
            throw new DataIOException("Article can't be a null");
        }
    }

    private void checkUnique(String articleTitle) throws DataIOException {
        if (findArticle(articleTitle) != null) {
            throw new DataIOException("Article with given title already exist");
        }
    }
}
